using System;
using System.Collections.Generic;
using System.Text;
using GetTogether.RichText;
using GetTogether.RichText.Interpreter;
using GetTogether.RichText.Converter.Image;
using System.Drawing.Imaging;
using GetTogether.RichText.Support;
using System.Drawing;
using GetTogether.RichText.Converter.Html;
using GetTogether.RichText.Sys.Application;
using System.IO;
using GetTogether.RichText.Parser;

namespace GetTogether.RichText
{
    public class ConverterEngine
    {
        private string _InterpreterLogFileName;

        public string InterpreterLogFileName
        {
            get { return _InterpreterLogFileName; }
            set { _InterpreterLogFileName = value; }
        }

        private string _ParserLogFileName;

        public string ParserLogFileName
        {
            get { return _ParserLogFileName; }
            set { _ParserLogFileName = value; }
        }

        public string ConvertRtf2HtmlFromStream(Stream stream,bool isSubHtml,bool isIgnoreFontStyle)
        {
            IRtfGroup rtfStructure = ParseRtfStream(stream);
            if (rtfStructure == null)
            {
                return string.Empty;
            }

            // interpreter logger
            RtfInterpreterListenerFileLogger interpreterLogger = null;
            if (!string.IsNullOrEmpty(InterpreterLogFileName))
            {
                interpreterLogger = new RtfInterpreterListenerFileLogger(InterpreterLogFileName);
            }

            // image converter
            RtfVisualImageAdapter imageAdapter = new RtfVisualImageAdapter(ImageFormat.Jpeg);
            RtfImageConvertSettings imageConvertSettings = new RtfImageConvertSettings(imageAdapter);
            imageConvertSettings.ScaleImage = true; // scale images
            RtfImageConverter imageConverter = new RtfImageConverter(imageConvertSettings);

            // rtf interpreter
            RtfInterpreterSettings interpreterSettings = new RtfInterpreterSettings();
            IRtfDocument rtfDocument = RtfInterpreterTool.BuildDoc(rtfStructure, interpreterSettings, interpreterLogger, imageConverter);

            // html converter
            RtfHtmlConvertSettings htmlConvertSettings = new RtfHtmlConvertSettings();
            htmlConvertSettings.ConvertScope = RtfHtmlConvertScope.Content;
            RtfHtmlConverter htmlConverter = new RtfHtmlConverter(rtfDocument);
            htmlConverter.IsSubHtml = true;
            htmlConverter.IsIgnoreFontFamily = isIgnoreFontStyle;
            return htmlConverter.Convert();
        }

        public string ConvertRtf2Html(string fileName)
        {
            // parser
            IRtfGroup rtfStructure = ParseRtf(fileName);
            if (rtfStructure == null)
            {
                return string.Empty;
            }

            // interpreter logger
            RtfInterpreterListenerFileLogger interpreterLogger = null;
            if (!string.IsNullOrEmpty(InterpreterLogFileName))
            {
                interpreterLogger = new RtfInterpreterListenerFileLogger(InterpreterLogFileName);
            }

            // image converter
            RtfVisualImageAdapter imageAdapter = new RtfVisualImageAdapter(ImageFormat.Jpeg);
            RtfImageConvertSettings imageConvertSettings = new RtfImageConvertSettings(imageAdapter);
            imageConvertSettings.ScaleImage = true; // scale images
            RtfImageConverter imageConverter = new RtfImageConverter(imageConvertSettings);

            // rtf interpreter
            RtfInterpreterSettings interpreterSettings = new RtfInterpreterSettings();
            IRtfDocument rtfDocument = RtfInterpreterTool.BuildDoc(rtfStructure, interpreterSettings, interpreterLogger, imageConverter);

            // html converter
            RtfHtmlConvertSettings htmlConvertSettings = new RtfHtmlConvertSettings();
            htmlConvertSettings.ConvertScope = RtfHtmlConvertScope.Content;
            RtfHtmlConverter htmlConverter = new RtfHtmlConverter(rtfDocument);
            return htmlConverter.Convert();
        }

        private IRtfGroup ParseRtf(string fileName)
        {
            IRtfGroup rtfStructure;

            using (FileStream stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                RtfParserListenerStructureBuilder structureBuilder = new RtfParserListenerStructureBuilder();
                RtfParser parser = new RtfParser(structureBuilder);
                parser.IgnoreContentAfterRootGroup = true; // support WordPad documents
                if (!string.IsNullOrEmpty(ParserLogFileName))
                {
                    parser.AddParserListener(new RtfParserListenerFileLogger(ParserLogFileName));
                }
                parser.Parse(new RtfSource(stream));
                rtfStructure = structureBuilder.StructureRoot;
            }
            return rtfStructure;
        }

        private IRtfGroup ParseRtfStream(Stream stream)
        {
            IRtfGroup rtfStructure;

            RtfParserListenerStructureBuilder structureBuilder = new RtfParserListenerStructureBuilder();
            RtfParser parser = new RtfParser(structureBuilder);
            parser.IgnoreContentAfterRootGroup = true; // support WordPad documents
            if (!string.IsNullOrEmpty(ParserLogFileName))
            {
                parser.AddParserListener(new RtfParserListenerFileLogger(ParserLogFileName));
            }
            parser.Parse(new RtfSource(stream));
            rtfStructure = structureBuilder.StructureRoot;

            return rtfStructure;
        }
    }

    class ProgramSettings
    {

        
        public ProgramSettings()
        {
            LoadApplicationArguments();
        } // ProgramSettings

        
        public bool IsHelpMode
        {
            get { return applicationArguments.IsHelpMode; }
        } // IsHelpMode

        
        public bool IsValid
        {
            get { return applicationArguments.IsValid; }
        } // IsValid

        
        public bool IsValidSourceFile
        {
            get
            {
                string sourceFile = SourceFile;
                return !string.IsNullOrEmpty(sourceFile) && File.Exists(sourceFile);
            }
        } // IsValidSourceFile

        
        public string SourceFile
        {
            get { return sourceFileArgument.Value; }
        } // SourceFile

        
        public string SourceFileNameWithoutExtension
        {
            get
            {
                string sourceFile = SourceFile;
                if (sourceFile == null)
                {
                    return null;
                }
                FileInfo fi = new FileInfo(sourceFile);
                return fi.Name.Replace(fi.Extension, string.Empty);
            }
        } // SourceFileNameWithoutExtension

        
        public string DestinationDirectory
        {
            get
            {
                string destinationDirectory = destinationDirectoryArgument.Value;
                if (string.IsNullOrEmpty(destinationDirectory) && IsValidSourceFile)
                {
                    FileInfo fi = new FileInfo(SourceFile);
                    return fi.DirectoryName;
                }
                return destinationDirectory;
            }
        } // DestinationDirectory

        
        public string StyleSheets
        {
            get { return styleSheetsArgument.Value; }
        } // StyleSheets	

        
        public string ImagesDirectory
        {
            get { return imagesDirectoryArgument.Value; }
        } // ImagesDirectory	

        
        public string ImagesPath
        {
            get
            {
                string imagesPath = DestinationDirectory;
                if (!string.IsNullOrEmpty(ImagesDirectory))
                {
                    imagesPath = Path.Combine(imagesPath, ImagesDirectory);
                }
                return imagesPath;
            }
        } // ImagesPath	

        
        public string ImageType
        {
            get { return imageTypeArgument.Value; }
        }

        
        public string ImageFileNamePattern
        {
            get
            {
                string imageFileNamePattern = SourceFileNameWithoutExtension + "{0}{1}";
                if (!string.IsNullOrEmpty(ImagesDirectory))
                {
                    imageFileNamePattern = Path.Combine(ImagesDirectory, imageFileNamePattern);
                }
                return imageFileNamePattern;
            }
        }

        
        public ImageFormat ImageFormat
        {
            get
            {
                ImageFormat imageFormat = ImageFormat.Jpeg;
                if (!string.IsNullOrEmpty(ImageType))
                {
                    switch (ImageType.ToLower())
                    {
                        case "jpg":
                            imageFormat = ImageFormat.Jpeg;
                            break;
                        case "gif":
                            imageFormat = ImageFormat.Gif;
                            break;
                        case "png":
                            imageFormat = ImageFormat.Png;
                            break;
                    }
                }
                return imageFormat;
            }
        }

        
        public Color? ImageBackgroundColor
        {
            get
            {
                string backgroundColorName = imageBackgroundColorNameArgument.Value;
                if (string.IsNullOrEmpty(backgroundColorName))
                {
                    return null;
                }

                Color backgroundColor = Color.FromName(backgroundColorName);
                if (!backgroundColor.IsKnownColor)
                {
                    return null;
                }
                return backgroundColor;
            }
        }

        
        public string CharacterEncoding
        {
            get { return characterEncodingArgument.Value; }
        }

        
        public Encoding Encoding
        {
            get
            {
                Encoding encoding = Encoding.UTF8;

                if (!string.IsNullOrEmpty(CharacterEncoding))
                {
                    switch (CharacterEncoding.ToLower())
                    {
                        case "ascii":
                            encoding = Encoding.ASCII;
                            break;
                        case "utf7":
                            encoding = Encoding.UTF7;
                            break;
                        case "utf8":
                            encoding = Encoding.UTF8;
                            break;
                        case "unicode":
                            encoding = Encoding.Unicode;
                            break;
                        case "bigendianunicode":
                            encoding = Encoding.BigEndianUnicode;
                            break;
                        case "utf32":
                            encoding = Encoding.UTF32;
                            break;
                        case "operatingsystem":
                            encoding = Encoding.Default;
                            break;
                    }
                }

                return encoding;
            }
        }
        
        public string CharacterSet
        {
            get { return characterSetArgument.Value; }
        }

        
        public string SpecialCharsRepresentation
        {
            get { return specialCharsRepresentationArgument.Value; }
        }

        
        public bool HasDestinationOutput
        {
            get { return SaveHtml || SaveImage; }
        }
        
        public bool SaveHtml
        {
            get { return saveHtmlArgument.Value; }
        }
        
        public bool SaveImage
        {
            get { return saveImageArgument.Value; }
        }
        
        public bool DisplayHtml
        {
            get { return displayHtmlArgument.Value; }
        }
        
        public string LogDirectory
        {
            get { return logDirectoryArgument.Value; }
        }
        
        public bool LogParser
        {
            get { return logParserArgument.Value; }
        }
        
        public bool LogInterpreter
        {
            get { return logInterpreterArgument.Value; }
        }
        
        public bool OpenHtml
        {
            get { return openHtmlArgument.Value; }
        }
        
        public bool ShowHiddenText
        {
            get { return showHiddenTextArgument.Value; }
        }
        
        public bool UseNonBreakingSpaces
        {
            get { return useNonBreakingSpacesArgument.Value; }
        }
        
        public bool ConvertVisualHyperlinks
        {
            get { return convertVisualHyperlinksArgument.Value; }
        }
        
        public bool UseInlineStyles
        {
            get { return useInlineStylesArgument.Value; }
        }
        
        public string VisualHyperlinkPattern
        {
            get { return visualHyperlinkPatternArgument.Value; }
        }
        
        public bool ExtendedImageScale
        {
            get { return extendedImageScaleArgument.Value; }
        }
        
        public string DocumentScope
        {
            get { return documentScopeArgument.Value; }
        }
        
        public bool UnscaledImages
        {
            get { return unscaledImagesArgument.Value; }
        } 
        
        public bool IgnoreDuplicatedFonts
        {
            get { return ignoreDuplicatedFontsArgument.Value; }
        } 
        
        public bool IgnoreUnknownFonts
        {
            get { return ignoreUnknownFontsArgument.Value; }
        }
        
        public RtfHtmlConvertScope ConvertScope
        {
            get
            {
                RtfHtmlConvertScope convertScope = RtfHtmlConvertScope.None;

                if (!string.IsNullOrEmpty(DocumentScope))
                {
                    string[] tokens = DocumentScope.Split(',');
                    foreach (string token in tokens)
                    {
                        switch (token.ToLower())
                        {
                            case "doc":
                            case "document":
                                convertScope |= RtfHtmlConvertScope.Document;
                                break;
                            case "html":
                                convertScope |= RtfHtmlConvertScope.Html;
                                break;
                            case "head":
                                convertScope |= RtfHtmlConvertScope.Head;
                                break;
                            case "body":
                                convertScope |= RtfHtmlConvertScope.Body;
                                break;
                            case "content":
                                convertScope |= RtfHtmlConvertScope.Content;
                                break;
                            case "*":
                            case "all":
                                convertScope |= RtfHtmlConvertScope.All;
                                break;
                        }
                    }
                }
                return convertScope;
            }
        } 
        
        public string BuildDestinationFileName(string path, string extension)
        {
            string sourceFileNameWithoutExtension = SourceFileNameWithoutExtension;
            if (sourceFileNameWithoutExtension == null)
            {
                return null;
            }

            return Path.Combine(
                string.IsNullOrEmpty(path) ? DestinationDirectory : path,
                sourceFileNameWithoutExtension + extension);
        } 
        
        private void LoadApplicationArguments()
        {
            applicationArguments.Arguments.Add(new HelpModeArgument());
            applicationArguments.Arguments.Add(sourceFileArgument);
            applicationArguments.Arguments.Add(destinationDirectoryArgument);
            applicationArguments.Arguments.Add(styleSheetsArgument);
            applicationArguments.Arguments.Add(imagesDirectoryArgument);
            applicationArguments.Arguments.Add(imageTypeArgument);
            applicationArguments.Arguments.Add(imageBackgroundColorNameArgument);
            applicationArguments.Arguments.Add(characterEncodingArgument);
            applicationArguments.Arguments.Add(characterSetArgument);
            applicationArguments.Arguments.Add(specialCharsRepresentationArgument);
            applicationArguments.Arguments.Add(saveHtmlArgument);
            applicationArguments.Arguments.Add(saveImageArgument);
            applicationArguments.Arguments.Add(logDirectoryArgument);
            applicationArguments.Arguments.Add(logParserArgument);
            applicationArguments.Arguments.Add(logInterpreterArgument);
            applicationArguments.Arguments.Add(displayHtmlArgument);
            applicationArguments.Arguments.Add(openHtmlArgument);
            applicationArguments.Arguments.Add(showHiddenTextArgument);
            applicationArguments.Arguments.Add(useNonBreakingSpacesArgument);
            applicationArguments.Arguments.Add(convertVisualHyperlinksArgument);
            applicationArguments.Arguments.Add(visualHyperlinkPatternArgument);
            applicationArguments.Arguments.Add(extendedImageScaleArgument);
            applicationArguments.Arguments.Add(documentScopeArgument);
            applicationArguments.Arguments.Add(useInlineStylesArgument);
            applicationArguments.Arguments.Add(unscaledImagesArgument);
            applicationArguments.Arguments.Add(ignoreDuplicatedFontsArgument);
            applicationArguments.Arguments.Add(ignoreUnknownFontsArgument);

            applicationArguments.Load();
        }
        
        // members
        private readonly ApplicationArguments applicationArguments = new ApplicationArguments();
        private readonly ValueArgument sourceFileArgument = new ValueArgument(ArgumentType.Mandatory);
        private readonly ValueArgument destinationDirectoryArgument = new ValueArgument();
        private readonly NamedValueArgument styleSheetsArgument = new NamedValueArgument("CSS");
        private readonly NamedValueArgument imagesDirectoryArgument = new NamedValueArgument("ID");
        private readonly NamedValueArgument imageTypeArgument = new NamedValueArgument("IT");
        private readonly NamedValueArgument imageBackgroundColorNameArgument = new NamedValueArgument("BC");
        private readonly NamedValueArgument characterEncodingArgument = new NamedValueArgument("CE");
        private readonly NamedValueArgument characterSetArgument = new NamedValueArgument("CS");
        private readonly NamedValueArgument specialCharsRepresentationArgument = new NamedValueArgument("SC");
        private readonly ToggleArgument saveHtmlArgument = new ToggleArgument("SH", true);
        private readonly ToggleArgument saveImageArgument = new ToggleArgument("SI", true);
        private readonly NamedValueArgument logDirectoryArgument = new NamedValueArgument("LD");
        private readonly ToggleArgument logParserArgument = new ToggleArgument("LP", false);
        private readonly ToggleArgument logInterpreterArgument = new ToggleArgument("LI", false);
        private readonly ToggleArgument displayHtmlArgument = new ToggleArgument("D", false);
        private readonly ToggleArgument openHtmlArgument = new ToggleArgument("O", false);
        private readonly ToggleArgument showHiddenTextArgument = new ToggleArgument("HT", false);
        private readonly ToggleArgument useNonBreakingSpacesArgument = new ToggleArgument("NBS", false);
        private readonly ToggleArgument convertVisualHyperlinksArgument = new ToggleArgument("CH", false);
        private readonly ToggleArgument useInlineStylesArgument = new ToggleArgument("IS", true);
        private readonly NamedValueArgument visualHyperlinkPatternArgument = new NamedValueArgument("HP");
        private readonly ToggleArgument extendedImageScaleArgument = new ToggleArgument("XS", false);
        private readonly NamedValueArgument documentScopeArgument = new NamedValueArgument("DS");
        private readonly ToggleArgument unscaledImagesArgument = new ToggleArgument("UI", false);
        private readonly ToggleArgument ignoreDuplicatedFontsArgument = new ToggleArgument("IDF", false);
        private readonly ToggleArgument ignoreUnknownFontsArgument = new ToggleArgument("IUF", false);

    }
}
